#include "Rectangle.h"
#include "Events.h"
#include <iostream>
#include <map>
#include <deque>
#include <fstream>
using namespace std;

typedef map<int,int> x_map;
typedef map<int,x_map> y_map;
typedef map<int,int> active_map;
typedef deque<CEvent> Tevents_list;
typedef deque<CRectangle> Trectangles_list;



// Input: An empty events list. event is top or bottom of a rectangle.
// The function creates an arranged events list by inserting every event in the right place.
// The function taked into acount the posibility that several rectangles can start at the 
// same line (but not at the same space).
void create_events_list(y_map &events_list,Tevents_list& event_list) 
{
	int in1=0, in2=0, in3=0;
	Tevents_list::iterator event_it=event_list.begin();
	while(event_it!=event_list.end())
	{
		if (events_list.find(event_it->GET_line_position()) == events_list.end())		//check if rectangle exist in the events list	
			events_list[event_it->GET_line_position()] = x_map();  // not exist => creating a new line (line and map to current events).
		events_list[event_it->GET_line_position()][event_it->GET_first_point()] = event_it->GET_second_point();	 // exist => just adding the new event to the correct line.
		event_it++;
	}
}

// Input: Active list - the existing rectangles at current line.
// Input: Current key - points on the current rectangle (to be erased).
// Input: Current_line - represent ehere are we in the sweep line proccess.
// The function calculates the spaces between the two rectangles that surounding the erased one.
int erase_calculate_space(active_map &active_list, int current_key, int current_line, fstream &fileapces)
{
	int space;
	active_map::iterator current_it, left_it, right_it;

	current_it = active_list.find(current_key);
	right_it = current_it;
	left_it  = current_it;
	if((current_it++ != active_list.begin()) && (current_it != active_list.end())) 
	{	// check whether the (going to be) erased rectangle is the left most or the right most, so we skip calculations.
		right_it++;		// the rectangle from the right.
		left_it--;		// the rectangle from the left.
		space = right_it->first - left_it->second;
	//	cout << current_line+1 << "\t" << left_it->second << "\t" << right_it->first << "\t" << space << endl;
		fileapces << left_it->second << " " << current_line+1 << " " << space << endl;
	}
	else
		space = NULL;
	return space;
}

// Input: Active list - the existing rectangles at current line.
// Input: Current key - points on the current rectangle (inserted).
// Input: Current_line - represent ehere are we in the sweep line proccess.
// The function calculates the spaces between the two rectangles that surounding the erased one.
int insert_calculate_spaces(active_map &active_list, int current_key, int current_line, fstream &fileapces)
{
	int space;
	active_map::iterator current_it, left_it, right_it;
	
	current_it = active_list.find(current_key);
	right_it = current_it;
	left_it  = current_it;
	if(current_it != active_list.begin())
	{	// check whether the (going to be) erased rectangle is the left most or the right most, so we skip calculations.
				
		left_it--;		// the rectangle from the left.
		space = current_it->first - left_it->second;
	//	cout << current_line << "\t" << left_it->second << "\t" << current_it->first << "\t" << space << endl;
		fileapces << left_it->second << " " <<  current_line << " " << space << endl;
	}
	right_it++;			// the rectangle from the right.
	if(right_it != active_list.end())
	{
		space = right_it->first - current_it->second;
	//	cout << current_line << "\t" << current_it->second << "\t" << right_it->first << "\t" << space << endl;
		fileapces << current_it->second << " " <<  current_line << " " << space << endl;
	}
	return 0;
}


// Input: Full arranged events list.
// The function run through all the events (x events in every y event).
// Everytime a rectangle starts or ends (event), it updates an active list and calculates the relevant spaces.
void create_active_list(y_map &events_list, fstream &fileapces)
{
	int current_key = NULL;
	int current_line = NULL;
	x_map x_events;
	active_map active_list;
	x_map::iterator x_it;
	y_map::iterator y_it;

	y_it = events_list.begin();								//first event
	while(y_it != events_list.end())						//run over all y-axis events
	{						
		x_events = y_it->second;							//get all events from the same time/y_axis
		x_it = x_events.begin();
		current_line = y_it->first;

		while(x_it != x_events.end())						//run over all x-axis events
		{									
			active_map::iterator current_x_int = active_list.find(x_it->first);
			if ( current_x_int == active_list.end())		//check if already exist. no => insert ; yes => erase.
			{
				active_list[x_it->first] = x_it->second;	//insert x-axis event (from the same y-axis)
				insert_calculate_spaces(active_list, x_it->first, current_line, fileapces);
			} 
			else		// x-axis event already exist => bottom of rect => erase from active list.
			{				
				current_key = current_x_int->first;
				erase_calculate_space(active_list, current_key, current_line, fileapces);
				active_list.erase(current_x_int);
			}
			x_it++;	//next x event
		}
		y_it++;		//next y event

		

	}
	events_list.clear();
	return ;
}

// The function read the rectangles from afile in format: x1 y1 x2 y2.
// Than it creates two files for x_events and y_events.
int read_rectangles(fstream& filerect, Trectangles_list& rect_list, Tevents_list& Xevent_list, Tevents_list& Yevent_list)
{
	int x1=0, x2=0, y1=0, y2=0;
	
	while(!filerect.eof())
	{
		filerect >> x1 >> y1 >> x2 >> y2;
		CRectangle rect(x1, y1, x2, y2);
		rect_list.push_back(rect);
		CEvent x_event1(y1, x1, x2);
		Xevent_list.push_back(x_event1);
		CEvent x_event2(y2, x1, x2);
		Xevent_list.push_back(x_event2);
		CEvent y_event1(x1, y1, y2);
		Yevent_list.push_back(y_event1);
		CEvent y_event2(x2, y1, y2);
		Yevent_list.push_back(y_event2);
	}
	return 0;
}


// The function makes the stdin/out read and write to files (instead to the screen).
int open_files(fstream &filerect, fstream &fileapcesx, fstream &fileapcesy)
{
	filerect.open ("rectangles.txt", fstream::in);
	if (filerect.is_open() == false)
		return -1;
	fileapcesx.open ("x_spaces.txt", fstream::out);
	if (fileapcesx.is_open() == false)
			return -1;
	fileapcesy.open ("y_spaces.txt", fstream::out);
	if (fileapcesy.is_open() == false)
			return -1;
	return 0;
}

void close_files(fstream &filerect, fstream &fileapcesx, fstream &fileapcesy)
{
	filerect.close();
	fileapcesx.close();
	fileapcesy.close();
}

int main ()
{
	fstream filerect, fileapcesx, fileapcesy;
	y_map events_list;
//	CRectangles rectangles; 
	Trectangles_list rect_list;
	Tevents_list Xevent_list, Yevent_list;


	open_files(filerect, fileapcesx, fileapcesy);
	read_rectangles(filerect, rect_list, Xevent_list, Yevent_list);
	// run all for vertical sweep-line
	create_events_list(events_list, Xevent_list);
	create_active_list(events_list, fileapcesx);

	// run all for horisontal sweep-line
	create_events_list(events_list, Yevent_list);
	create_active_list(events_list, fileapcesy);
	close_files(filerect, fileapcesx, fileapcesy);
	return 0;
}
